package cc.rengu.igas.channel.alipay.core.packswitch;

import cc.rengu.igas.channel.alipay.common.constant.AlipayParamConstant;
import cc.rengu.igas.channel.alipay.common.constant.AlipayTreeNodeConstant;
import cc.rengu.igas.channel.alipay.common.constant.AlipayTxnNumConstant;
import cc.rengu.igas.channel.alipay.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.alipay.core.realize.AlipaySignService;
import cc.rengu.igas.channel.alipay.core.realize.impl.AlipaySignServiceImpl;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.CertInfoMapper;
import cc.rengu.oltp.service.common.dao.DstChannelCfgMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.CertInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstChannelCfgMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.CertInfo;
import cc.rengu.oltp.service.common.entity.DstChannelCfg;
import cc.rengu.oltp.service.common.entity.SecPlanInfo;
import cc.rengu.oltp.service.common.entity.SrcChannelInfo;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.utility.util.RedisUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.net.URLDecoder;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class CupsAlipayNoticePackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {


    @Override
    public byte[] afterOutgoPackSwitch(byte[] arg0) throws Exception {
        XmlTreeUtil tree = new XmlTreeUtil();
        String respCode = tree.getXmlTreeStringValue("respCode");
        return "SUCCESS".getBytes();
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        return 0;
    }

    @Override
    public int afterInComPackSwitch() throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        //赋值默认机构、渠道、交易细分
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String appId = xmlTreeUtil.getXmlTreeStringValue(AlipayTreeNodeConstant.ALIPAY_APPID);
        String sysSrcId = ChannelEnum.UPAL.getChannelType();
        DstChannelCfgMapper dstChannelCfgMapper = new DstChannelCfgMapperImpl();
        List<DstChannelCfg> dstChannelCfgList = dstChannelCfgMapper.loadAllDstChannelCfg();
        if (dstChannelCfgList == null || dstChannelCfgList.isEmpty()) {
            rglog.error("无通道配置信息，未知法人行交易");
            return -1;
        }
        Predicate<DstChannelCfg> chnlIdFilter = p -> ChannelEnum.UPAL.getChannelType().equals(p.getDstChannelId());
        Predicate<DstChannelCfg> appIdFilter = p -> appId.equals(p.getAppId());
        dstChannelCfgList = dstChannelCfgList.stream().filter(chnlIdFilter.and(appIdFilter)).collect(Collectors.toList());
        if (dstChannelCfgList.isEmpty()) {
            rglog.error("根据通道id<{}>、支付宝appid<{}>查无无通道配置信息，未知法人行交易", ChannelEnum.UPAL.getChannelType(), appId);
            return -1;
        }
        String instId = dstChannelCfgList.get(0).getInstId();
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.INST_ID, instId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID, sysSrcId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.MSG_SRC_ID, AlipayParamConstant.TUNL_ID_CUPSALIP);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_ID, sysSrcId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.BIZ_TYPE, AppParamConstant.DEFAULT_BIZ_TYPE);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.HEADER_INST_ID, instId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.HEADER_SRC_SYS_ID, AlipayParamConstant.TUNL_ID_CUPSALIP);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.HEADER_CHANNEL_ID, sysSrcId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.HEADER_BIZ_TYPE, AppParamConstant.DEFAULT_BIZ_TYPE);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, AlipayTxnNumConstant.T00CH300);
        String sign = xmlTreeUtil.getXmlTreeStringValue("sign");
        if (null == sign) {
            rglog.debug("无签域，不进行签名校验!");
            return -1;
        }
        String signBlock = xmlTreeUtil.getXmlTreeStringValue("signBlock");
        /* 获取通道配置信息 */
        String srcChannelKey = instId + AlipayParamConstant.TUNL_ID_CUPSALIP + "*";
        SrcChannelInfo srcChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ACQ_INFO_CACHE, srcChannelKey), SrcChannelInfo.class);
        if (null == srcChannelInfo || !srcChannelInfo.getTransChannelStatus().equalsIgnoreCase(AppParamConstant.YES)) {
            rglog.error("支付渠道<{}-{}>未配置或已停用！", AlipayParamConstant.TUNL_ID_CUPSALIP, (null == srcChannelInfo) ? "" : srcChannelInfo.getSrcChannelName());
            throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
        }

        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, srcChannelInfo.getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.SEC_PLAN_INFO_LIST, JSON.toJSONString(secPlanInfoList));
            /* 获取敏感信息加密证书 */
            Optional<SecPlanInfo> checkSignSecPlanOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(AlipayParamConstant.VERIFY_CERT_TYPE)).findFirst();
            if (checkSignSecPlanOpt.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(checkSignSecPlanOpt.get().getInstId() + checkSignSecPlanOpt.get().getSecPlanId() + checkSignSecPlanOpt.get().getSecPlanType());
                if (null == certInfo) {
                    rglog.error("获取通道证书<{}>配置信息失败!", srcChannelInfo.getSecPlanId());
                    throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
                }
                AlipaySignService alipaySignService = new AlipaySignServiceImpl();
                /* 验证签名 */
                if (alipaySignService.verifySignString(sign, signBlock, certInfo)) {
                    rglog.info("签名验证成功!");
                    return 0;
                } else {
                    rglog.error("签名验证失败!");
                    return -1;
                }

            }
        }

        return 0;

    }

    @Override
    public byte[] beforeInComPackSwitch(byte[] arg0) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        String input;
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        ArrayList<String> arrayList = new ArrayList<>();
        Map<String, String> revMap;
        JSONObject jsonObject = new JSONObject();
        String signBlock;
        String charset;
        int i;
        /*获取编码类型，未做解码处理*/
        input = new String(arg0);
        revMap = parseJsonString(input);
        if (revMap.get("charset") != null) {
            rglog.trace("编码为:{}", revMap.get("charset"));
            charset = revMap.get("charset");
        } else {
            rglog.trace("默认UTF-8编码...");
            charset = "utf-8";
        }
        /*根据&符，对支付宝返回字段分组*/
        String[] str = input.split("&", -1);
        for (i = 0; i < str.length; i++) {
            String[] str1 = str[i].split("=", -1);
            /*value进行URL解码*/
            String str2 = URLDecoder.decode(str1[1], charset);
            /*存入内部是中，key和value*/
            xmlTreeUtil.setXmlTreeStringValue(str1[0], str2);
            /*验签中去掉sign、sign_type、cert_id*/
            if (!"sign".equals(str1[0]) && !"sign_type".equals(str1[0]) && !"cert_id".equals(str1[0])) {
                arrayList.add(str1[0] + "=" + str2 + "&");
            }
            /*value是否是list数据类型，进行处理*/
            if (str2 != null && str2.startsWith("[")) {
                try {
                    JSONArray jsonArray = JSONArray.parseArray(str2);
                    jsonObject.put(str1[0], jsonArray);
                } catch (Exception e) {
                    rglog.error("非json数组");
                    jsonObject.put(str1[0], str2);
                }
            } else {
                jsonObject.put(str1[0], str2);
            }
        }
        /*验签字符串排序处理*/
        String[] strArray = arrayList.toArray(new String[0]);
        Arrays.sort(strArray);
        StringBuilder stringBuffer = new StringBuilder();
        for (i = 0; i < strArray.length; i++) {
            stringBuffer.append(strArray[i]);
        }
        /*生成验签字符串*/
        signBlock = stringBuffer.substring(0, stringBuffer.length() - 1);
        rglog.debug("signBlock=[{}]", signBlock);
        xmlTreeUtil.setXmlTreeStringValue("signBlock", signBlock);
        return JSON.toJSONString(jsonObject).getBytes();
    }

    /**
     * 将还分隔符&的kv字符串转换成Map对象
     *
     * @param kvString 字符串
     * @return MAP对象
     */
    private Map<String, String> parseJsonString(String kvString) {
        Map<String, String> map = new HashMap<>();
        int len = kvString.length();
        StringBuilder temp = new StringBuilder();
        char curChar;
        String key = null;
        boolean isKey = true;
        boolean isOpen = false;//值里有嵌套
        char openName = 0;
        if (len > 0) {
            for (int i = 0; i < len; i++) {// 遍历整个带解析的字符串
                curChar = kvString.charAt(i);// 取当前字符
                if (isKey) {// 如果当前生成的是key
                    if (curChar == '=') {// 如果读取到=分隔符
                        key = temp.toString();
                        temp.setLength(0);
                        isKey = false;
                    } else {
                        temp.append(curChar);
                    }
                } else {// 如果当前生成的是value
                    if (isOpen) {
                        if (curChar == openName) {
                            isOpen = false;
                        }
                    } else {//如果没开启嵌套
                        if (curChar == '{') {//如果碰到，就开启嵌套
                            isOpen = true;
                            openName = '}';
                        }
                        if (curChar == '[') {
                            isOpen = true;
                            openName = ']';
                        }
                    }
                    if (curChar == '&' && !isOpen) {// 如果读取到&分割符,同时这个分割符不是值域，这时将map里添加
                        putKeyValueToMap(temp, isKey, key, map);
                        temp.setLength(0);
                        isKey = true;
                    } else {
                        temp.append(curChar);
                    }
                }
            }
            putKeyValueToMap(temp, isKey, key, map);
        }
        return map;
    }

    /**
     * 将KEY及VALUE值设置对Map对象
     *
     * @param temp  VALUE值
     * @param isKey 是否为KEY标识
     * @param key   KEY值
     * @param map   MAP对象
     */
    private static void putKeyValueToMap(StringBuilder temp, boolean isKey, String key, Map<String, String> map) {
        if (isKey) {
            key = temp.toString();
            if (key.length() == 0) {
                throw new RuntimeException("String format illegal");
            }
            map.put(key, "");
        } else {
            if (key.length() == 0) {
                throw new RuntimeException("String format illegal");
            }
            map.put(key, temp.toString());
        }
    }
}
